import { exec, spawn } from 'child_process'
import async from 'async'
import { ipcMain } from 'electron'


let event = null
export function registerIpcMain() {
    ipcMain.handle('on-start-app', async (e, snArray, wholeActivitys) => {
        event = e
        return adbStartApp(snArray, wholeActivitys, (result) => {
            event.sender.send('adb-app-start-result', result);
        })
    })
}

function logStartApp(log) {
    console.log(log)
    if (event) {
        event.sender.send('adb-app-start-log', log);
    }
}
/**
 * 等待指定的毫秒数后，使用Promise解决（resolve）
 *
 * @param ms 等待的毫秒数
 * @returns 返回一个新的Promise对象，该对象在指定的毫秒数后解决（resolve）
 */
function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// 创建一个函数，接受adb命令作为参数，并返回一个Promise
function executeAdbCommand(adbCommand) {
    console.log(`exec command: ${adbCommand}`);
    return new Promise((resolve, reject) => {
        exec(adbCommand, (error, stdout, stderr) => {
            if (error) {
                // 如果命令执行出错，则拒绝Promise并返回错误信息
                reject({ error, stderr });
            } else {
                // 如果命令执行成功，则解析Promise并返回命令的输出
                resolve(stdout);
            }
        });
    });
}

function adbForceStop(sn, packageName) {
    executeAdbCommand(`adb -s ${sn} shell am force-stop ${packageName}`);
}

function adbAmStart(sn, wholeActivity) {
    executeAdbCommand(`adb -s ${sn} shell am start -n ${wholeActivity}`);
    ///topResumedActivity=ActivityRecord\{[^\}]*\s+u\d\s+([^\s]+)/
}

//adb shell dumpsys activity | findstr topResumedActivity
/**
 * 获取指定设备序列号的当前顶层应用包名
 *
 * 调用示例：
 * adbGetTopPackageName(deviceIds).then((results) => {
        console.log(results)
    }).catch((err) => {
        console.log(err)
    })
 * @param snArray 设备序列号数组
 * @returns 返回Promise对象，resolve值为顶层应用包名数组
 */
export async function adbGetTopPackageName(snArray) {
    // 创建一个Promise数组来保存所有的异步操作
    const promises = snArray.map(async sn => {
        const stdout = await executeAdbCommand(`adb -s ${sn} shell dumpsys activity | findstr Resumed:`);
        // 使用正则表达式匹配包名
        const match = stdout.match(/Resumed: ActivityRecord\{[^\}]*\s+u\d\s+([^\s\/]+)/);
        if (match && match[1]) {
            return { sn, packageName: match[1] };
        }
        return { sn, packageName: null };
    });

    // 使用Promise.all等待所有的Promise完成，并将结果收集到packageNames数组中
    const results = await Promise.all(promises);
    return results.filter(results_1 => results_1.packageName !== null);
}

/**
 * 从给定的包名中获取启动类的全类名
 *
 * @param sn 设备序列号
 * @param packageName 应用包名
 * @returns 返回包名对应的主活动（Launcher Activity）字符串，若执行adb命令失败则返回'error executing adb command'
 */
export async function adbGetWholeActivityFromPackageName(sn, packageName) {
    try {
        if ('com.android.launcher3'.includes(packageName)) return 'com.android.launcher3/.Launcher'
        const packageInfo = await executeAdbCommand(`adb -s ${sn} shell dumpsys package ${packageName}`);
        const lines = packageInfo.split('\n');
        let launcherActivity = 'not found';

        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            if (!line || line.trim() === '') continue;
            if (line.includes('Category: \"android.intent.category.LAUNCHER\"')) {
                // 往上解析四行
                for (let j = 1; j <= 4; j++) { // 注意JavaScript中的数组索引是从0开始的，所以这里用j <= 4
                    const findLineIndex = i - j;
                    if (findLineIndex < 0 || !lines[findLineIndex] || lines[findLineIndex].trim() === '' || !lines[findLineIndex].includes(packageName + '/')) continue;
                    const splits = lines[findLineIndex].split(packageName);
                    // 注意JavaScript中数组索引访问不会抛出异常，但如果找不到分隔符，splits[1]可能是undefined
                    if (splits.length > 1) {
                        const activity = splits[1].split('filter')[0].trim(); // 添加trim()去除可能的前后空格
                        launcherActivity = packageName + activity; // 通常Android的组件名包含包名和类名，用'/'分隔
                        break;
                    }
                }
                break;
            }
        }
        return launcherActivity;
    } catch (error) {
        console.error('Error executing adb command:', error);
        return 'error executing adb command';
    }
}

/**
 * 使用管道执行adb logcat命令，并监听输出，获取冷启动Displayed返回时间
 *
 * @returns 返回一个对象，包含子进程（process）和杀死进程的方法（kill）
 */
export function executeAdbLogcatWithPipe(sn) {
    // 清除缓冲区日志
    executeAdbCommand(`adb -s ${sn} logcat -c`)
    // 执行adb logcat命令，筛选ActivityTaskManager tag， 并监听输出
    const logcatActivityTaskManager = spawn('adb', ['-s', sn, 'logcat', '-s', 'ActivityTaskManager:V']);

    let displayLogs = '';

    // 处理输出
    logcatActivityTaskManager.stdout.on('data', (data) => {
        const lines = data.toString().split(/\r?\n/);
        lines.forEach(line => {
            if (line.includes('Displayed')) {
                logStartApp({
                    device: sn,
                    log: line,
                })
                // 记录日志，里面包含启动数据信息
                displayLogs += line + '\n';
            }
        });
    });

    // 处理stderr
    logcatActivityTaskManager.stderr.on('data', (data) => {
        console.error(`Device: ${sn}, stderr: ${data}`);
    });

    // 处理进程关闭
    logcatActivityTaskManager.on('close', () => {
        // 清除缓冲区日志
        executeAdbCommand(`adb -s ${sn} logcat -c`)
        console.log(`Device: ${sn}, logcat process exited.`);
    });

    return {
        process: logcatActivityTaskManager,
        kill: () =>  {
            logcatActivityTaskManager.kill()
            console.log(`Killed process for device: ${sn}`)
            // 返回包含数据信息的logcat日志
            return displayLogs;
        }
    };
}

export async function adbStartApp(deviceSNs, wholeActivitys, callback) {
    /**
     * 流程：
     * 0.遍历deviceSNs，对每一个设备执行 1
     * 1.遍历wholeActivitys，对每一个wholeActivity执行 2-5
     * 2.先启动一次
     * 3.调用executeAdbLogcatWithPipe，获取到logcat进程
     * 4.for (5次) { 执行forcestop + 包名，执行start wholeActivity }
     * 5.调用kill方法，结束logcat进程，获取返回的displayLogs进行解析
     */
    console.log(`Start to start app, deviceSNs: ${deviceSNs}`)
    async.eachLimit(deviceSNs, 3, async (deviceSN) => {
        console.log(`Start to start app on device: ${deviceSN}`)
        for (const wholeActivity of wholeActivitys) {
            const packageName = wholeActivity.split('/')[0] // 获取包名
            const activityNameParts = wholeActivity.split('/')[1].split('.')
            const activityName = activityNameParts[activityNameParts.length - 1]  // 获取activity简单类名
            // 2. 先启动一次————去除了，不启动了，避免出现六次log，导致用户看到的进度条不精准
            //adbAmStart(deviceSN, wholeActivity);
            //await wait(2500)
            adbForceStop(deviceSN, packageName);

            // 3. 调用executeAdbLogcatWithPipe，获取到logcat进程
            const process = executeAdbLogcatWithPipe(deviceSN)
            await wait(1000)

            // 4. for (5次) { 执行forcestop + 包名，执行start wholeActivity }
            for (let i = 0; i < 5; i++) {
                adbForceStop(deviceSN, packageName);
                await wait(1000)
                adbAmStart(deviceSN, wholeActivity);
                await wait(2500)
            }

            //5.调用kill方法，结束logcat进程，获取返回的displayLogs进行解析
            const displayLogs = process.kill()

            //退回到launcher
            adbForceStop(deviceSN, packageName);
            // 清除缓冲区日志
            executeAdbCommand(`adb -s ${deviceSN} logcat -c`)
            await wait(1000)
            // const displayLogs = `07-07 18:30:00.989   946   976 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity for user 0: +1s536ms
            // 07-07 18:30:04.492   946   976 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity for user 0: +1s499ms
            // 07-07 18:30:08.071   946   976 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity for user 0: +1s547ms
            // 07-07 18:30:11.601   946   976 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity for user 0: +1s550ms
            // 07-07 18:30:15.050   946   976 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity for user 0: +1s494ms`

             // 使用split方法按换行符'\n'分割字符串为数组
            const logEntries = displayLogs.split('\n');

            // 提取时间并转换为毫秒
            function parseTime(timeStr) {
                timeStr = timeStr.replace(/\+/g, '') // 去掉所有'+'
                timeStr = timeStr.replace(/ms$/, '') // 去掉所有'ms'
                
                let seconds = 0;
                let milliseconds = 0;

                if (timeStr.includes('s')) {
                    const split = timeStr.split('s')
                    seconds = parseInt(split[0], 10)
                    milliseconds = parseInt(split[1], 10)
                } else {
                    milliseconds = parseInt(timeStr, 10)
                }

                return (seconds * 1000) + milliseconds
            }

            // 提取并处理时间
            let timeData = logEntries
                .filter(entry => {
                    // 使用正则表达式查找"Displayed ... <time>"的模式
                    const match = entry.match(/Displayed (.*?) (\+\d+s?\d*ms?)/);
                    return match && match[1].includes(packageName) && match[1].includes(activityName); // 替换为具体的活动名称检查
                })
                .map(entry => {
                    // 提取时间字符串并转换为毫秒
                    const [, timeStr] = entry.match(/Displayed .* (\+\d+s?\d*ms?)/);
                    return parseTime(timeStr);
                })
                // 过滤掉非法的或零毫秒的时间
                .filter(time => time > 0)
            if (timeData.length > 5) {
                timeData = timeData.slice(-5);
            }

            // 计算平均值
            let average = 0
            if (timeData.length > 0) {
                average = (timeData.reduce((sum, time) => sum + time, 0) / timeData.length).toFixed(2);
                average = Number(average);
            }

            const result = {
                sn: deviceSN,
                packageName: packageName,
                data: timeData,
                average: average
            };
            
            // 返回结果
            callback(result)
        }
    })
}

/**
 * 从adb命令的输出中提取设备ID
 *
 * @param adbOutput adb命令的输出字符串
 * @returns 返回一个包含设备ID的字符串数组
 */
function extractDeviceIds(adbOutput) {
    // 按换行符分割输出为数组
    const lines = adbOutput.trim().split('\n');
    
    // 过滤出包含设备ID的行，并提取设备ID
    const deviceIds = lines
      .map(line => {
        // 去除行首尾的空白字符，并分割成数组
        const parts = line.trim().split(/\s+/);
        
        // 检查是否存在两个元素，并且第二个元素是'device'
        if (parts.length > 1 && parts[1].toLowerCase() === 'device') {
          // 返回第一个元素作为设备ID
          return parts[0];
        }
      })
      // 过滤掉undefined和空值
      .filter(deviceId => typeof deviceId === 'string' && deviceId.length > 0);
  
    return deviceIds;
}

export function adbDevices() {
    // 返回一个Promise对象
    return new Promise((resolve, reject) => {
        // 执行adb devices命令，获取设备列表
        exec('adb devices', (error, stdout) => {
            // 如果执行过程中发生错误
            if (error) {
                // 拒绝Promise并返回错误信息
                reject(error);
            // 如果没有错误
            } else {
                // 解析设备ID并解析Promise
                resolve(extractDeviceIds(stdout));
            }
        });
    });
}